# Copyright (C) 2000-2001 The OpenRPG Project
#
#    openrpg-dev@lists.sourceforge.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# --
#
# File: mapper/images.py
# Author: OpenRPG
# Maintainer:
# Version:
#   $Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $
#
# Description:
#
__version__ = "$Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $"

import urllib
import Queue
import thread
from threading import Lock
import time
from orpg.orpg_wx import *
from orpg.orpgCore import *

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance()

class ImageHandlerClass(object):
    __cache = {}
    __fetching = {}
    __queue = Queue.Queue(0)
    __lock = Lock()

    def load(self, path, image_type, imageId):
        # Load an image, with a intermideary fetching image shown while it loads in a background thread
        if self.__cache.has_key(path):
            return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2]).ConvertToBitmap()
        if not self.__fetching.has_key(path):
            self.__fetching[path] = True
            #Start Image Loading Thread
            thread.start_new_thread(self.__loadThread, (path, image_type, imageId))
        else:
            if self.__fetching[path] is True:
                thread.start_new_thread(self.__loadCacheThread, (path, image_type, imageId))
        return wx.Bitmap(open_rpg.get_component("dir_struct")["icon"] + "fetching.png", wx.BITMAP_TYPE_PNG)

    def directLoad(self, path):
        # Directly load an image, no threads
        if self.__cache.has_key(path):
            return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2]).ConvertToBitmap()
        uriPath = urllib.unquote(path)
        try:
            d = urllib.urlretrieve(uriPath)
            # We have to make sure that not only did we fetch something, but that
            # it was an image that we got back.
            if d[0] and d[1].getmaintype() == "image":
                self.__cache[path] = (path, d[0], d[1].gettype(), None)
                return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2]).ConvertToBitmap()
            else:
                open_rpg.get_component('log').log("Image refused to load or URI did not reference a valid image: " + path, ORPG_GENERAL, True)
                return None
        except IOError:
            open_rpg.get_component('log').log("Unable to resolve/open the specified URI; image was NOT loaded: " + path, ORPG_GENERAL, True)
            return None

    def cleanCache(self):
        # Shrinks the Cache down to the proper size
        try:
            cacheSize = int(open_rpg.get_component('settings').get_setting("ImageCacheSize"))
        except:
            cacheSize = 32
        cache = self.__cache.keys()
        cache.sort()
        for key in cache[cacheSize:]:
            del self.__cache[key]

    def flushCache(self):
        #    This function will flush all images contained within the image cache.
        self.__lock.acquire()
        try:
            keyList = self.__cache.keys()
            for key in keyList:
                del self.__cache[key]
        finally:
            self.__lock.release()
        urllib.urlcleanup()

#Private Methods
    def __loadThread(self, path, image_type, imageId):
        uriPath = urllib.unquote(path)
        self.__lock.acquire()
        try:
            d = urllib.urlretrieve(uriPath)
            # We have to make sure that not only did we fetch something, but that
            # it was an image that we got back.
            if d[0] and d[1].getmaintype() == "image":
                self.__cache[path] = (path, d[0], d[1].gettype(), imageId)
                self.__queue.put((self.__cache[path], image_type, imageId))
                if self.__fetching.has_key(path):
                    del self.__fetching[path]
            else:
                open_rpg.get_component('log').log("Image refused to load or URI did not reference a valid image: " + path, ORPG_GENERAL, True)
                self.__fetching[path] = False
        except IOError:
            self.__fetching[path] = False
            open_rpg.get_component('log').log("Unable to resolve/open the specified URI; image was NOT laoded: " + path, ORPG_GENERAL, True)
        finally:
            self.__lock.release()

    def __loadCacheThread(self, path, image_type, imageId):
        try:
            st = time.time()
            while self.__fetching.has_key(path) and self.__fetching[path] is not False:
                time.sleep(0.025)
                if (time.time()-st) > 120:
                    open_rpg.get_component('log').log("Timeout: " + path, ORPG_GENERAL, True)
                    break
        except:
            self.__fetching[path] = False
            open_rpg.get_component('log').log("Unable to resolve/open the specified URI; image was NOT loaded: " + path, ORPG_GENERAL, True)
            return
        self.__lock.acquire()
        try:
            open_rpg.get_component('log').log("Adding Image to Queue from Cache: " + str(self.__cache[path]), ORPG_DEBUG)
            self.__queue.put((self.__cache[path], image_type, imageId))
        finally:
            self.__lock.release()

#Property Methods
    def _getCache(self):
        return self.__cache

    def _getQueue(self):
        return self.__queue

#Properties
    Cache = property(_getCache)
    Queue = property(_getQueue)

ImageHandler = singleton(ImageHandlerClass)
